#include "biplTypes.h"
#include <string>
#include <sstream>
#include <iostream>

/// implicitly convert to bool
pairTypes::operator bool() const
{
	if (fx == 0.0f && fy == 0.0f)
		return false;
	else
		return true;
}

/// implicitly convert to other types
pairTypes::operator stringTypes() const
{
	return toString();
}

/// output stream operator
std::ostream&
	operator<<(std::ostream&out, const pairTypes& s)
{
	out << s.toString();
	return out;
}

/// Negation Operator
pairTypes operator- (const pairTypes &s)
{
	return pairTypes(-s.fx, -s.fy);
}

/// Arithmetic Operators
const pairTypes operator+(const pairTypes& lhs, const pairTypes& rhs)
{
	return pairTypes(lhs.fx + rhs.fx, lhs.fy + rhs.fy);
}

const pairTypes operator-(const pairTypes& lhs, const pairTypes& rhs)
{
	return pairTypes(lhs.fx - rhs.fx, lhs.fy - rhs.fy);
}

const pairTypes operator/(const pairTypes& lhs, const pairTypes& rhs)
{
	return pairTypes(lhs.fx / rhs.fx, lhs.fy / rhs.fy);
}

const pairTypes operator*(const pairTypes& lhs, const pairTypes& rhs)
{
	return pairTypes(lhs.fx * rhs.fx, lhs.fy * rhs.fy);
}

const pairTypes operator%(const pairTypes& lhs, const pairTypes& rhs)
{
	return pairTypes(fmod(lhs.fx, rhs.fx), fmod(lhs.fy, rhs.fy));
}

/// Arithmetic Assignment Operators
pairTypes& operator+=(pairTypes& lhs, const pairTypes& rhs)
{
	lhs.fx += rhs.fx;
	lhs.fy += rhs.fy;
	return lhs;
}

pairTypes& operator-=(pairTypes& lhs, const pairTypes& rhs)
{
	lhs.fx -= rhs.fx;
	lhs.fy -= rhs.fy;
	return lhs;
}

pairTypes& operator*=(pairTypes& lhs, const pairTypes& rhs)
{
	lhs.fx *= rhs.fx;
	lhs.fy *= rhs.fy;
	return lhs;
}

pairTypes& operator/=(pairTypes& lhs, const pairTypes& rhs)
{
	lhs.fx /= rhs.fx;
	lhs.fy /= rhs.fy;
	return lhs;
}

pairTypes& operator%=(pairTypes& lhs, const pairTypes& rhs)
{
	lhs.fx = fmod(lhs.fx, rhs.fx);
	lhs.fy = fmod(lhs.fy, rhs.fy);
	return lhs;
}

/// Equality Operators
boolTypes operator==(const pairTypes& left, const boolTypes& right)
{
	return boolTypes(left.toBoolean() == right);
}

boolTypes operator!=(const pairTypes& left, const boolTypes& right)
{
	return boolTypes(left.toBoolean() != right);
}

boolTypes operator==(const boolTypes& left, const pairTypes& right)
{
	return boolTypes(left == right.toBoolean());
}

boolTypes operator!=(const boolTypes& left, const pairTypes& right)
{
	return boolTypes(left != right.toBoolean());
}

boolTypes operator==(const pairTypes& left, const pairTypes& right)
{
	return boolTypes(left.fx == right.fx && left.fy == right.fy);
}

boolTypes operator!=(const pairTypes& left, const pairTypes& right)
{
	return boolTypes(left.fx != right.fx || left.fy != right.fy);
}

/// Logical Operators
boolTypes operator!(const pairTypes& s)
{
	return !s.toBoolean();
}

boolTypes operator&&(const pairTypes& left, const pairTypes& right)
{
	return left.toBoolean() && right.toBoolean();
}

boolTypes operator||(const pairTypes& left, const pairTypes& right)
{
	return left.toBoolean() || right.toBoolean();
}

/// Type conversion functions
boolTypes pairTypes::toBoolean() const
{
	if (fx == 0.0f && fy == 0.0f)
		return boolTypes(false);
	else
		return boolTypes(true);
}

pairTypes pairTypes::toPair() const
{
	return pairTypes(*this);
}

stringTypes pairTypes::toString() const
{
	std::stringstream ss(std::stringstream::in | std::stringstream::out);
	ss << '[' << fx << ", " << fy << ']';
	
	return stringTypes(ss.str());
}